package com.example.friendfindertwo;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import android.util.Log;

import model.Category;
import model.Event;
import model.Friend;

import com.example.friendfindertwo.application.StartApplication;
import com.google.android.gms.maps.model.LatLng;
import com.parse.FindCallback;
import com.parse.ParseException;
import com.parse.ParseGeoPoint;
import com.parse.ParseObject;
import com.parse.ParseQuery;
import com.parse.SaveCallback;

public class ParseDatabase {

	public ParseObject userTable;
	public ParseObject eventTable;
	public ParseObject friendsTable;
	public ParseObject JoinEventTable;
	private static String name;
	private static String accountName;

	public ParseDatabase()
	{
		//initialize parse object
		userTable = new ParseObject("userTable");
		eventTable = new ParseObject("event");
		friendsTable = new ParseObject("friends");
		JoinEventTable = new ParseObject("JoinEventTable");

	}

	public boolean isUserInDataBase()
	{
		ParseQuery<ParseObject> query = ParseQuery.getQuery("userTable");
		// If the user isn't in the database the users is saved to the database with the email adresse. 
		try {
			if (query.whereEqualTo("account_name",accountName).count() == 0) {
				return false;
			}
			else return true;
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return false;	
	}

	public void logUserConnection() {
		// Gets a list of all the users stored in the database

		if(isUserInDataBase())
		{
			//user is already in database
			ParseObject userRow = getUserRow(accountName);
			userRow.put("online", true);
			userRow.saveInBackground();
		}
		else
		{
			//create a new user (new row)
			userTable.put("account_name",accountName);
			//userTable.put("name", name);
			userTable.put("online", true);
			userTable.saveInBackground();
		}
	}


	public void updateLocationDatabase(LatLng currentPosition)
	{
		double Lat = currentPosition.latitude;
		double Lng = currentPosition.longitude;

		ParseObject userRow = getUserRow(accountName);
		ParseGeoPoint location = new ParseGeoPoint(Lat,Lng);
		userRow.put("location",location);
		userRow.saveInBackground();
	}

	public ParseObject getUserRow(String name)
	{
		ParseQuery<ParseObject> query = ParseQuery.getQuery("userTable");

		try {
			ParseObject userRow = (ParseObject)query.whereEqualTo("account_name", name).getFirst();
			return userRow;
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public static String getAccountName()
	{
		return accountName;
	}

	public void setAccountName(String account)
	{
		accountName = account;
	}

	public static String getName()
	{
		return name;
	}

	public void setName(String realname)
	{
		name = realname;
	}

	public void setOnline()
	{
		ParseObject userRow = getUserRow(accountName);
		userRow.put("online", true);
		userRow.saveInBackground();
	}

	public void setOffline()
	{
		ParseObject userRow = getUserRow(accountName);
		userRow.put("online", false);
		userRow.saveInBackground();
	}

	public String getLastUpdateTime(String userName)
	{
		ParseObject userRow = getUserRow(userName);

		return userRow.getUpdatedAt().toString();		
	}

	public LatLng getLastLocation(String userName)
	{
		// TODO: check if its the right way to handle if there is no last location
		LatLng location = new LatLng(0,0);

		ParseObject userRow = getUserRow(userName);
		if(userRow.getParseGeoPoint("location") != null){
			location = new LatLng(userRow.getParseGeoPoint("location").getLatitude(), userRow.getParseGeoPoint("location").getLongitude());
		}

		return location;
	}

	public int countDataBaseSize()
	{
		ParseQuery<ParseObject> query = ParseQuery.getQuery("userTable");
		try {
			return query.find().size();
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * 
	 * @param loc
	 * @param eventBegin
	 * @param eventEnd
	 * @param description
	 * @param title
	 * @param isPublic
	 */
	public String saveEventOnDataBase(LatLng loc, java.util.Date eventBegin, java.util.Date eventEnd, String description, String title, Boolean isPublic)
	{
		ParseGeoPoint location = new ParseGeoPoint(loc.latitude,loc.longitude);

		eventTable.put("account_name",getAccountName());
		eventTable.put("location", location);
		eventTable.put("event_begin",eventBegin);
		eventTable.put("event_end",eventEnd);
		eventTable.put("description",description);
		eventTable.put("title",title);
		eventTable.put("public",isPublic);
		eventTable.saveInBackground();
		ParseQuery<ParseObject> query = ParseQuery.getQuery("event");
		query.orderByAscending("createdAt");
		String objectId="";
		try{
			List<ParseObject> parseList = query.find();
			
			for(ParseObject obj : parseList){
				objectId=obj.getString("objectId");
			}
		}
		catch(Exception e){
			Log.e("ParseDatabase.saveEventOnDataBase", e.toString());
		}
		return objectId;
	}
	/**
	 *@param ev 
	 **/
	public String saveEventOnDataBase(Event ev)
	{
		ParseGeoPoint location = new ParseGeoPoint(ev.getPosition().latitude,ev.getPosition().longitude);
		eventTable.put("category", ev.getCategorie());
		eventTable.put("account_name",getAccountName());
		eventTable.put("location", location);
		eventTable.put("event_begin",ev.getStartDate());
		eventTable.put("event_end",ev.getEndDate());
		eventTable.put("description",ev.getDescription());
		eventTable.put("title",ev.getTitle());
		eventTable.put("public",ev.isPublic());
		eventTable.put("placeName", ev.getPlaceName());
		eventTable.saveInBackground();
		
		ParseQuery<ParseObject> query = ParseQuery.getQuery("event");
		query.orderByAscending("createdAt");
		String objectId="";
		try{
			List<ParseObject> parseList = query.find();
			
			for(ParseObject obj : parseList){
				objectId=obj.getString("objectId");
			}
		}
		catch(Exception e){
			Log.e("ParseDatabase.saveEventOnDataBase", e.toString());
		}
		return objectId;

	}

	/**
	 * 
	 * @return
	 */
	public String[] getFriends()
	{		
		ParseQuery<ParseObject> queryRelation1 = ParseQuery.getQuery("friends");
		queryRelation1.whereEqualTo("user1", accountName);
		queryRelation1.whereEqualTo("isOk1",true);
		queryRelation1.whereEqualTo("isOk2", true);

		int count1=0;
		try {
			count1 = queryRelation1.find().size();
		} catch (ParseException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		String[] userList1= new String[count1];
		try {
			List<ParseObject> friendsList = queryRelation1.find();
			for(int i=0;i<friendsList.size();i++)
			{
				userList1[i] = (String) friendsList.get(i).get("user2");
			}
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		ParseQuery<ParseObject> queryRelation2 = ParseQuery.getQuery("friends");
		queryRelation2.whereEqualTo("user2", accountName);
		queryRelation2.whereEqualTo("isOk1",true);
		queryRelation2.whereEqualTo("isOk2", true);

		int count2=0;
		try {
			count2 = queryRelation2.find().size();
		} catch (ParseException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		String[] userList2= new String[count2];
		try {
			List<ParseObject> friendsList2 = queryRelation2.find();
			for(int i=0;i<friendsList2.size();i++)
			{
				userList2[i] = (String) friendsList2.get(i).get("user1");
			}
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		String[] userList = new String[count1+count2];
		System.arraycopy(userList1,0, userList, 0, count1);
		System.arraycopy(userList2,0, userList, count1, count2);

		return userList;
	}

	/**
	 * 
	 * @param search
	 * @return
	 */
	public String[] getUser(String search)
	{		
		ParseQuery<ParseObject> query = ParseQuery.getQuery("userTable");
		query.whereContains("account_name", search);
		query.whereNotEqualTo("account_name", accountName);

		int count=0;

		try {
			count = query.find().size();
		} catch (ParseException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		final String[] userList= new String[count];
		try {
			List<ParseObject> friendsList = query.find();
			for(int i=0;i<friendsList.size();i++)
			{
				userList[i] = (String) friendsList.get(i).get("account_name");
			}
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return userList;
	}

	/**
	 * 
	 * @return
	 */
	public String[] getFriendListOnline()
	{
		String[] friendListOnline = new String[]{};
		String[] friendList = new String[getFriends().length];
		friendList = getFriends();
		List<ParseQuery<ParseObject>> queries = new ArrayList<ParseQuery<ParseObject>>();

		int i;
		for(i=0;i<friendList.length;i++)
		{
			ParseQuery<ParseObject> query = ParseQuery.getQuery("userTable");
			query.whereEqualTo("account_name", friendList[i]);
			query.whereEqualTo("online", true);
			queries.add(query);
		}

		int count=0;
		try {
			ParseQuery<ParseObject> mainQuery = ParseQuery.or(queries);
			count = mainQuery.find().size();

			friendListOnline = new String[count];

			List<ParseObject> friendListOnline2 = mainQuery.find();
			for(i=0;i<friendListOnline2.size();i++)
			{
				friendListOnline[i] = (String) friendListOnline2.get(i).get("account_name");
				//Log.d("friends",friendListOnline[i]);
			}
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch(IllegalArgumentException e){
			e.printStackTrace();
		}

		return friendListOnline;
	}

	/**
	 * 
	 * @return
	 */
	public Event[] getAllEvent()
	{		
		ArrayList<String> friends = new ArrayList<String>();
		String[] friendsList = getFriends();

		for(int i=0;i<friendsList.length;i++)
		{
			friends.add(getFriends()[i]);
		}

		ParseQuery<ParseObject> myFriendsEvent = ParseQuery.getQuery("eventTable");
		myFriendsEvent.whereContainedIn("account_name", friends);

		ParseQuery<ParseObject> publicEvent = ParseQuery.getQuery("eventTable");
		publicEvent.whereEqualTo("public",true);

		List<ParseQuery<ParseObject>> queries = new ArrayList<ParseQuery<ParseObject>>();
		queries.add(myFriendsEvent);
		queries.add(publicEvent);

		ParseQuery<ParseObject> mainQuery = ParseQuery.or(queries);

		int count=0;
		try {
			count = mainQuery.find().size();
		} catch (ParseException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		final Event[] eventList= new Event[count];
		try {
			List<ParseObject> eventList2 = mainQuery.find();
			for(ParseObject po : eventList2){
				//Log.i("database", po.get("title").toString());
			}
			for(int i=0;i<eventList2.size();i++)
			{
				LatLng location = new LatLng(eventList2.get(i).getParseGeoPoint("location").getLatitude(), eventList2.get(i).getParseGeoPoint("location").getLongitude());

				eventList[i].setDescription((String) eventList2.get(i).get("description"));
				eventList[i].setPosition(location);
				eventList[i].setTitle((String) eventList2.get(i).get("title"));
				eventList[i].setStartDate(eventList2.get(i).getDate("event_begin"));
				eventList[i].setEndDate(eventList2.get(i).getDate("event_end"));


			}
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return eventList;
	}

	/**
	 * 
	 * @return
	 */
	public List<Event> getEvents(){
		List <Event> events = new ArrayList<Event>(); 
		List<ParseObject> parseResult=new ArrayList<ParseObject>();
		ParseQuery<ParseObject> publicEvent = ParseQuery.getQuery("event");
		HashMap<String,Friend> friendList = getAllUsers();
		//publicEvent.whereEqualTo("public",true);
		try{
			parseResult=publicEvent.find();

		}catch(ParseException e){
			e.printStackTrace();
		}
		int i=0;
		Log.i("ParseDatabase query size", ""+parseResult.size());


		for(ParseObject obj :parseResult)
		{	
			Friend creator = friendList.get(obj.getString("account_name"));
//			i++;
			Event event = new Event((String)obj.get("title"),
					(String)obj.get("description"),
					obj.getString("category"),
					convertGeoPointToLatLng((ParseGeoPoint)obj.get("location")),
					(Date)obj.get("event_begin"),
					(Date)obj.get("event_end"),
					(String)obj.get("placeName"),
					creator,
					(boolean)obj.getBoolean("public"));
			event.setObjectId(obj.getObjectId());
			events.add(event);
			//			Log.i("ParseDatabse.event account_name", obj.getString("account_name"));
			//			Log.i("ParseDatabse.event description", obj.getString("description"));
//			Log.i("ParseDatabase.counter",""+i);

		}

		Log.i("ParseDatabase.getEvents.toString",events.toString());

		return events;
	}

	public LatLng convertGeoPointToLatLng(ParseGeoPoint geoPoint)
	{
		return new LatLng(geoPoint.getLatitude(),geoPoint.getLongitude());
	}

	/**
	 * method to get a friend by name.
	 * @param name
	 * @return
	 */
	public Friend getFriendByName(String name){
		ParseQuery<ParseObject> query = ParseQuery.getQuery("userTable");


		//		Log.i("getFriendByName name", name);

		Friend f = new Friend();

		//execute query
		List<ParseObject> friend;
		try {
			query.whereContains("account_name", name);
			
			friend = query.find();

			if(friend != null && !friend.isEmpty()){
				//			Log.i("getFriendByName not null or empty", friend.get(0).getString("account_name"));
				LatLng ll = new LatLng(friend.get(0).getParseGeoPoint("location").getLatitude(), friend.get(0).getParseGeoPoint("location").getLongitude());
				f = new Friend(friend.get(0).getString("account_name"), ll, friend.get(0).getBoolean("online"));
			}else{
				//			Log.i("getFriendByName NULL", name);

			}
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			Log.i("getFriendByName error", e.toString());
			//e.printStackTrace();
		} catch (Exception e){
			Log.i("getFriendByName error", e.toString());
		}
		//		Log.i("getFriendByName", f.toString());
		return f;
	}

	public HashMap<String,Friend> getAllUsers(){
		HashMap <String,Friend> userList = new HashMap <String,Friend>();
		ParseQuery<ParseObject> query = ParseQuery.getQuery("userTable");

		List<ParseObject> parseFriend;
		try {
			parseFriend = query.find();
			Log.i("ParseDatabse.getAllUSER SIZE", ""+parseFriend.size());
			for(ParseObject obj : parseFriend)
			{
				Log.i("ParseDatabse.getAllUSER account name", obj.getString("account_name"));
				Log.i("ParseDatabse.getAllUSER location", ""+obj.getParseGeoPoint("location"));
				userList.put((String) obj.getString("account_name"),
						new Friend(
								(String) obj.getString("account_name"),
								(LatLng)convertGeoPointToLatLng(obj.getParseGeoPoint("location")),
								true
								));
			}
		}
		catch(Exception e){
			Log.e("ParseDatabse.getAllUsers catch", e.toString());
		}

		return userList;
	}
	/**
	 * 
	 * @param friend
	 */
	public void sendRequest(String friend)
	{
		Log.d("friends","send request to "+friend);
		friendsTable.put("user1", accountName);
		friendsTable.put("isOk1",true);
		friendsTable.put("user2",friend);
		friendsTable.put("isOk2",false);
		friendsTable.saveInBackground();
	}

	/**
	 * method to get all categories from database
	 * @return
	 */
	public List<Category> getAllCategories(){
		ParseQuery<ParseObject> query = ParseQuery.getQuery("Category");
		List<ParseObject> result = new ArrayList<ParseObject>();
		List<Category> allCategories = new ArrayList<Category>();

		try {
			result = query.find();
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if(result != null){
			for(ParseObject po : result){
				allCategories.add(new Category(po.getString("name")));
			}
		}

		return allCategories;
	}

	public void acceptRequest(String name)
	{		
		ParseObject userRow = null;
		ParseQuery<ParseObject> query = ParseQuery.getQuery("friends");
		query.whereEqualTo("user2", accountName);
		query.whereEqualTo("isOk2", false);

		try {
			userRow = (ParseObject)query.whereEqualTo("user1", name).getFirst();
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		userRow.put("isOk2", true);
		userRow.saveInBackground();
	}

	public String[] getRequest()
	{
		ParseQuery<ParseObject> query1 = ParseQuery.getQuery("friends");
		query1.whereEqualTo("user2", accountName);
		query1.whereEqualTo("isOk2", false);

		int count=0;
		try {
			count = query1.find().size();
		} catch (ParseException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		String[] requests = new String[count];

		try {
			List<ParseObject> requests2 = query1.find();
			for(int i=0;i<requests2.size();i++)
			{
				requests[i] = (String) requests2.get(i).get("user1");
			}
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return requests;
	}

	public void deleteFriend(String name)
	{
		ParseQuery<ParseObject> query1 = ParseQuery.getQuery("friends");
		query1.whereEqualTo("user1", accountName);
		query1.whereEqualTo("user2", name);
		query1.whereEqualTo("isOk1", true);
		query1.whereEqualTo("isOk2", true);

		ParseQuery<ParseObject> query2 = ParseQuery.getQuery("friends");
		query2.whereEqualTo("user1", name);
		query2.whereEqualTo("user2", accountName);
		query2.whereEqualTo("isOk1", true);
		query2.whereEqualTo("isOk2", true);

		List<ParseQuery<ParseObject>> queries = new ArrayList<ParseQuery<ParseObject>>();
		queries.add(query1);
		queries.add(query2);

		ParseQuery<ParseObject> mainQuery = ParseQuery.or(queries);
		try {
			ParseObject friendRelation = mainQuery.getFirst();
			Log.d("friends","user deleted = "+friendRelation.get("user1"));
			friendRelation.deleteInBackground();
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	public Event getEventByAccountAndTitle(String account_name, String title){
		List<ParseObject> parseResult=new ArrayList<ParseObject>();
		ParseQuery<ParseObject> publicEvent = ParseQuery.getQuery("event");
		publicEvent.whereEqualTo("account_name", account_name);
		publicEvent.whereEqualTo("title", title);
		Event resultEvent = new Event();
		
		try {
			parseResult = publicEvent.find();
			
			resultEvent = new Event(parseResult.get(0).getString("title"), 
					parseResult.get(0).getString("description"),
					parseResult.get(0).getString("category"), 
					convertGeoPointToLatLng(parseResult.get(0).getParseGeoPoint("location")),
					parseResult.get(0).getDate("event_begin"), 
					parseResult.get(0).getDate("event_end"),
					parseResult.get(0).getString("eventName"),
					getFriendByName(parseResult.get(0).getString("account_name")), 
					parseResult.get(0).getBoolean("public"));
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return resultEvent;
		
	}
	public void addInEvent(String ObjectId)
	{
		//ParseQuery<ParseObject> query = ParseQuery.getQuery("JoinEventTable");
		JoinEventTable.put("eventObjectId", ObjectId);
		JoinEventTable.put("account_name", accountName);
		JoinEventTable.saveInBackground();
	}
	
	public List<Friend> getPeopleInEvent(String ObjectId)
	{
		Log.i("ParseDatabase.getPeopleInEvent", "start function:"+ObjectId);
		List<Friend> friendList = new ArrayList<Friend>();
		ParseQuery<ParseObject> query = ParseQuery.getQuery("JoinEventTable");
		query.whereEqualTo("eventObjectId", ObjectId);
		try{
			List<ParseObject> parseResult = query.find();
			Log.i("ParseDatabase.getPeopleInEvent", ""+parseResult.size());
			for(ParseObject obj : parseResult){
				Friend friend=getFriendByName(obj.getString("account_name"));
				friendList.add(friend);
			}
		}catch(Exception e)
		{
			Log.e("getPeopleInEvent error",e.toString());
		}
		return friendList;
	}
	
	
}
